/*
 *  Copyright 2012 yura.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

package org.opu.odg.dg.incomingdata;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.opu.odg.dg.impl.DocumentGenerationContext;
import org.opu.odg.dg.runtimedata.VariableHolder;
import org.simpleframework.xml.ElementArray;
import org.simpleframework.xml.Root;

/**
 *
 * @author yura
 */
@Root(name="custom")
public class CustomContentDescription extends ContentDescription {
    @ElementArray(name="headers", entry="header", required=false)
    private String headers[] = new String[]{};
    @ElementArray(name="values", entry="value", required=false)
    private String data[][] = new String[][]{{}};
    private Map<String, Integer> headerMap;

    private CustomContentDescription() {
        // for simple framework
    }

    public CustomContentDescription(String[] headers, String[][] datap) {
        this.headers = headers;
        this.data = datap;
    }

    public String[][] getData() {
        return data;
    }

    public void setData(String[][] data) {
        this.data = data;
    }

    public String[] getHeaders() {
        return headers;
    }

    public void setHeaders(String[] headers) {
        this.headers = headers;
    }

    @Override
    public Iterable<ContextIteration> asIterable(DocumentGenerationContext context,
            VariableHolder variableHolder) {

        headerMap = new HashMap<String, Integer>();
        if (headers != null) {
            for (int i = 0; i < headers.length; i++) {
                headerMap.put(headers[i], i);
            }
        }

        final ArrayWraper array = new ArrayWraper(data);

        return new Iterable<ContextIteration>() {

            @Override
            public Iterator<ContextIteration> iterator() {
                return new Iterator<ContextIteration>() {
                    private int position = -1;

                    @Override
                    public boolean hasNext() {
                        return position + 1 < array.getHeight();
                    }

                    @Override
                    public ContextIteration next() {
                        position ++;
                        return new ContextIteration() {

                            @Override
                            public String get(String name) {
                                if (ContextIteration.ITERATION.equals(name)) {
                                    return String.valueOf(iteration());
                                }
                                return array.get(position, headerMap.get(name));
                            }

                            @Override
                            public String get(int index) {
                                return array.get(position, index - 1);
                            }

                            @Override
                            public Collection<String> getAll() {
                                return Arrays.asList(array.get(position));
                            }

                            @Override
                            public int iteration() {
                                return position + 1;
                            }
                        };
                    }

                    @Override
                    public void remove() {
                        throw new UnsupportedOperationException("Not supported.");
                    }
                };
            }
        };
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final CustomContentDescription other = (CustomContentDescription) obj;
        if (!Arrays.deepEquals(this.headers, other.headers)) {
            return false;
        }
        if (!Arrays.deepEquals(this.data, other.data)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + Arrays.deepHashCode(this.headers);
        hash = 97 * hash + Arrays.deepHashCode(this.data);
        return hash;
    }

    @Override
    public void close() throws IOException {
    }

    @Override
    public CustomContentDescription clone() {
        return new CustomContentDescription(headers, data);
    }

    class ArrayWraper {
        String data[][];

        public ArrayWraper(String[][] data) {
            this.data = data;
        }

        String get(int i, Integer j) {
            if (j == null) {
                return null;
            }

            try {
                if (data != null && data.length > i
                        && data[i] != null && data[i].length > j) {
                    return data[i][j];
                }
            } catch (Exception e) {
            }
            return null;
        }
        
        String[] get(int i) {
            try {
                if (data != null && data.length > i) {
                    return data[i];
                }
            } catch (Exception e) {
            }
            return new String[]{};
        }

        /**
         * Return amout of columns
         */
        int getWidth() {
            if (data != null && data[0] != null) {
                return data[0].length;
            }
            return 0;
        }

        /**
         * Return amout of rows
         */
        int getHeight() {
            if (data != null) {
                return data.length;
            }
            return 0;
        }
    }

}
